/**
 * Created by woziji00226 on 2024-11-28 15:16:18.
 */


class GUI_StackWoodGamePlayMain_W26 extends GUI_15001 {
    public static PLUGIN_GUI_GAMEPLAY: number = 15001;

    /**
     * 木头堆
     */
    private _woodStack: Array<GameSprite_Wood_W26> = [];

    /**
     * 正在游玩中
     */
    private _playing: boolean = false;

    /**
     * 切下的木头下落的时间
     */
    private _splitWoodDownTimeMs = 200;

    /**
     * 可以显示在屏幕上的木头数量
     */
    private _maxVisableWoodCount = 15;

    /**
     * 木头下落的偏移（叠在其他木头上）
     */
    private _WoodDownOffset = 3;

    private _data: {
        woodCount: number,
        score: number,
        level: number,
        combo: number,
    } = {
            woodCount: 0,
            score: 0,
            level: 0,
            combo: 0
        }

    private _score: {
        completed: number,
        perfet: number,
        combo: number
    }
        = {
            completed: 30,
            perfet: 5,
            combo: 1,
        }

    constructor() {
        super();

        this.firstWood.visible = false;
        this.gameOverContainer.visible = false;

        this.pushButton.on(EventObject.CLICK, this, this.putdownWood);

        this.restartGameButton.on(EventObject.CLICK, this, this.restartGame);

        os.add_ENTERFRAME(this.onUpdate, this);

        this.restartGame();
    }

    /**
     * 开始游戏
     */
    public startGame() {
        this._playing = true;
        this.gameOverContainer.visible = false;

        this.combo = 0;
        this.level = 0;
        this.score = 0;
        this._data.woodCount = 1;

        //生成第一块木头
        var firstWood = new GameSprite_Wood_W26();
        firstWood.x = this.firstWood.x;
        firstWood.y = this.firstWood.y;
        //firstWood.originalWidth = width;

        //放入第一个木头
        this.pushWood(firstWood);

        //放入第二个木头，这个木头开始悬浮
        this.readyNewWood();
        GameAudio.stopBGM();
        GameAudio.playBGM("asset/audio/bgm/Epic_1.ogg", 1, 9999, true, 2000, 1);
    }

    /**
     * 暂停游戏
     */
    public pauseGame() {
        this._playing = false;
    }

    /**
     * 停止游戏
     */
    public stopGame() {
        this._playing = false;
        var wood = this._woodStack.shift();
        while (wood != null) {
            wood.dispose();
            this.visibleContainer.removeChild(wood);
            wood = this._woodStack.shift();
        }
        this._woodStack.length = 0;
        GameAudio.stopBGM(true, 2000);
    }

    /**
     * 重启游戏
     */
    public restartGame() {
        this.stopGame();
        this.startGame();
    }

    public gameover() {
        this.stopGame();
        this.gameOverContainer.visible = true;
        this.resultMsg.text = `  你获得了${this._data.score}分，达到了${this._data.level}等级，完成了${this._data.combo}次连击！`
    }


    /**
     * 帧更新函数
     */
    private onUpdate() {
        //不显示的时候不运行
        if (this.visible === false) {
            return;
        }
        if (this.isPlaying === false) {
            return;
        }

        //更新移动部分
        this.updateWoodMove();

        //更新下落部分
        this.updateWoodDown();
    }

    /**
     * 更新木头左右移动
     */
    private updateWoodMove() {

        if (this._woodStack.length <= 1) {
            //超过两个才动
            return;
        }

        if (this.lastWood.status !== WoodStatus_W26.Float) {
            //木头不是浮动状态的情况下不可以移动
            return;
        }

        //根据左右方向得到木头下一步x要移动到的位置
        var increment = this.lastWood.speed * this.calculationMoveIncrement();
        this.lastWood.x += increment;

        //超出右边 方向向左
        if (this.lastWood.x >= this.getNearWoodRightX(this.lastWood)) {
            this.lastWood.x = this.getNearWoodRightX(this.lastWood);
            this.lastWood.speed = WoodSpeed_W26.RightToLeft;
        }

        //超出左边 方向向右
        if (this.lastWood.x <= this.getNearWoodLeftX(this.lastWood)) {
            this.lastWood.x = this.getNearWoodLeftX(this.lastWood);
            this.lastWood.speed = WoodSpeed_W26.LeftToRight;
        }
    }

    /**
     * 放下最上面一个木头
     */
    private putdownWood() {
        if (this._woodStack.length <= 1) {
            //超过两个才能放
            return;
        }

        if (this.lastWood.status !== WoodStatus_W26.Float) {
            //木头不是浮动状态的情况下不可以放下
            return;
        }

        this.lastWood.status = WoodStatus_W26.Down;
    }

    /**
     * 更新木头落下
     */
    private updateWoodDown() {
        if (this._woodStack.length <= 1) {
            //超过两个才能放
            return;
        }

        if (this.lastWood.status !== WoodStatus_W26.Down) {
            //木头不是放下状态的情况下不可以下落
            return;
        }

        var increment = 1 * this.calculationDownIncrement();
        this.lastWood.y += increment;

        //检测碰撞
        if (this.checkDownCollision()) {
            //重置下木头的位置
            this.lastWood.y = this.getNearLastLastWoodTopY() + this._WoodDownOffset;
            //+ Math.round(Math.random() * 5) + 5;

            if (this.isOddUsingBitwise(this._data.woodCount)) {
                this.visibleContainer.removeChild(this.lastWood);
                this.visibleContainer.addChildAt(this.lastWood, 0);
            }

            //下落了就禁止了
            this.lastWood.status = WoodStatus_W26.Static;
            //被切割下的木头
            var splitWood = this.lastWood.subtract(this.lastlastWood);
            if (splitWood != null && splitWood.woodWidth > 2) {
                this.playSplitWoodAnimation(splitWood);
            }

            //计算perfect 连击
            if (splitWood == null || splitWood.woodWidth < 7) {
                //perfect
                this.combo += 1;
                this.score += this._score.perfet;

                var globalPoint = (this.lastWood.parent as UIRoot).localToGlobal(new Point(this.lastWood.x + this.lastWood.woodWidth / 2, this.lastWood.y))
                this.playTextAnimation("perfect!", globalPoint.x, globalPoint.y);
                GameAudio.playSE('asset/audio/se/Get_1.ogg');
            }
            else {
                this.combo = 0;
            }

            //计算分数
            this.score += Math.floor(this.lastWood.splitPer * this._score.completed) + (this.combo * this._score.combo);

            if (this.lastWood.woodWidth > 0) {
                GameAudio.playSE('asset/audio/se/Jump_pedal.ogg');
                //准备下一个木头 延迟200ms
                Callback.New(this.readyNewWood, this).delayRun(this._splitWoodDownTimeMs);
            }
            else {
                //寄
                this.gameover();
            }
        }
    }

    /**
     * 判断是否是奇数
     */
    private isOddUsingBitwise(num) {
        return (num & 1) === 1;
    }

    /**
     * 播放切割的木头下落动画
     * @param wood 
     */
    private playSplitWoodAnimation(wood: GameSprite_Wood_W26): void {
        this.visibleContainer.addChildAt(wood, 0);
        Tween.to(wood, { alpha: 0, y: wood.y + 40 }, this._splitWoodDownTimeMs, Ease.sineIn, Callback.New((wood) => {
            this.visibleContainer.removeChild(wood);
            wood.dispose();
        }, this, [wood]));
    }

    /**
     * 播放漂浮字动画
     */
    private playTextAnimation(text, x, y) {
        var textSprite = new UIString();
        textSprite.color = '#FF0000';
        textSprite.fontSize = 18;
        textSprite.smooth = true;
        textSprite.text = text;
        textSprite.x = x - textSprite.textWidth / 2;
        textSprite.y = y;

        stage.addChild(textSprite);

        Tween.to(textSprite, { y: textSprite.y - 40, alpha: 1 }, 400, Ease.strongOut, Callback.New(() => {
            textSprite.dispose();
            stage.removeChild(textSprite);
        }, this))
    }

    /**
     * 检测碰撞
     * @return [boolean] 
     */
    private checkDownCollision(): boolean {
        return this.lastWood.y > this.getNearLastLastWoodTopY();
    }

    /**
     * 计算下落
     * @return [number] 
     */
    private calculationDownIncrement(): number {
        return 10;
    }

    /**
     * 计算移动的增量
     * math.log(x)*2 是一个函数图像，一开始变化快一些，到顶以后变化缓慢。
     * @return [number] 
     */
    private calculationMoveIncrement(): number {
        var r = Math.log(this._data.woodCount) * 0.6;
        //trace(r);
        return r;
    }

    /**
     * 准备一个新木头
     * @param width 新木头的宽度
     */
    private readyNewWood() {

        if (this.isPlaying === false) {
            //游戏没有运行的时候，不可以准备新的木头
            return;
        }

        if (this.lastWood.status === WoodStatus_W26.Down) {
            //最后一个木头在下落的时候，不可以准备新的木头
            return;
        }

        if (this.lastWood.status === WoodStatus_W26.Float) {
            //最后一个木头在浮动的时候，不可以准备新的木头
            return;
        }

        if (this._woodStack.length > this._maxVisableWoodCount) {
            //全体下降
            this.pushWood(this.createWood(this.lastWood.woodWidth));
            Callback.New(() => {
                this.decreaseAllWood();
                if (this.currentFirstWood.y > this.visibleContainer.height + 100) {
                    this.shiftWood();
                }
            }, this).delayRun(this._splitWoodDownTimeMs * 0.5);
        }
        else {
            this.pushWood(this.createWood(this.lastWood.woodWidth));
        }
    }

    /**
     * 创建新木头
     * @param width 
     * @return [GameSprite_Wood_W26] 
     */
    private createWood(width: number): GameSprite_Wood_W26 {
        var wood = new GameSprite_Wood_W26();
        wood.status = WoodStatus_W26.Float;
        if (width !== undefined) {
            wood.woodWidth = width;
            wood.originalWidth = width;
        }

        //随机获取 0 和 1 分别代表左边出现或者右边出现
        var rf = Math.round(Math.random());
        if (rf === 0) {
            //左边出现
            wood.x = this.getNearWoodLeftX(wood);
            wood.speed = WoodSpeed_W26.LeftToRight;
        }
        else {
            //右边出现
            wood.x = this.getNearWoodRightX(wood);
            wood.speed = WoodSpeed_W26.RightToLeft;
        }

        //设置图片
        wood.setWoodSource(this.woodSource);

        //至于高度就是比最上面那个稍微高一点
        wood.y = this.getNearLastWoodTopY();

        this._data.woodCount += 1;
        this.level = Math.floor(this._data.woodCount / 10);

        return wood;
    }

    /**
     * 降下所有木头
     */
    private decreaseAllWood() {
        var downHeight = this.currentFirstWood.woodHeight - this._WoodDownOffset;
        for (var i = 0; i < this._woodStack.length; i++) {
            var wood = this._woodStack[i];
            Tween.to(wood, { y: wood.y + downHeight }, this._splitWoodDownTimeMs, Ease.strongIn, Callback.New(() => {

            }, this));
        }
    }


    /**
     * 堆一个木头到最上方
     * @param wood 
     * @return [boolean] 
     */
    private pushWood(wood: GameSprite_Wood_W26): boolean {
        if (this._woodStack.indexOf(wood) == -1) {
            this._woodStack.push(wood);
            this.visibleContainer.addChild(wood);
            this._woodStack.shift
            return true;
        }
        return false;
    }

    /**
     * 去除最开头的木头
     */
    private shiftWood() {
        var index = this._woodStack.indexOf(this.currentFirstWood);
        if (index == -1) return;
        var woods: Array<GameSprite_Wood_W26> = this._woodStack.splice(index, 1);
        this.visibleContainer.removeChild(woods[0]);
        woods[0].dispose();
    }

    private refreshGameData() {
        this.scoreText.text = this._data.score.toString();
        this.levelText.text = this._data.level.toString();
        this.comboText.text = this._data.combo.toString();
    }

    /**
     * 得到wood能靠近最左边的位置
     * @param wood 
     * @return [number] 
     */
    private getNearWoodLeftX(wood: GameSprite_Wood_W26): number {
        return 0;
    }

    /**
     * 得到wood能靠近最右边的位置
     * @param wood 
     * @return [number] 
     */
    private getNearWoodRightX(wood: GameSprite_Wood_W26): number {
        return this.visibleContainer.width - wood.woodWidth;
    }

    /**
     * 获得最接近最后一个木头的上方的位置
     * @param wood 
     * @return [number] 
     */
    private getNearLastWoodTopY(): number {
        return this.lastWood.y - 30;
    }

    /**
     * 获取最近的第二个木头，就是最后一个木头，底下那个木头，最贴近的位置
     * @return [number] 
     */
    private getNearLastLastWoodTopY(): number {
        return this.lastlastWood.y - this.lastWood.woodHeight;
    }

    /**
     * 随机获取wood图片
     */
    private get randomWoodSource(): number {
        //向下取整，从woodList里随机选一个
        var index = Math.floor(Math.random() * WorldData.woodList.length);
        return index;
    }

    /**
     * 获取wood图片
     * @return [number] 
     */
    private get woodSource(): number {
        return this._data.woodCount % WorldData.woodList.length;
    }

    /**
     * 获取最顶上的木头
     * @return [GameSprite_Wood_W26] 
     */
    private get lastWood(): GameSprite_Wood_W26 {
        return this._woodStack[this._woodStack.length - 1];
    }

    /**
     * 获取倒数第二个木头
     * @return [GameSprite_Wood_W26] 
     */
    private get lastlastWood(): GameSprite_Wood_W26 {
        return this._woodStack[this._woodStack.length - 2];
    }

    /**
     * 获取第一木头
     * @return [GameSprite_Wood_W26] 
     */
    private get currentFirstWood(): GameSprite_Wood_W26 {
        return this._woodStack[0];
    }

    /**
     * 获得可视容器
     * @return [UIRoot] 
     */
    private get visibleContainer(): UIRoot {
        return this.woods;
    }

    /**
     * 是否正在游玩
     */
    public get isPlaying() {
        return this._playing;
    }

    private get score() {
        return this._data.score;
    }

    private get level() {
        return this._data.level;
    }

    private get combo() {
        return this._data.combo;
    }

    private set score(value) {
        this._data.score = value;
        this.refreshGameData();
    }

    private set level(value) {
        this._data.level = value;
        this.refreshGameData();
    }

    private set combo(value) {
        this._data.combo = value;
        this.refreshGameData();
    }
}
